﻿#include "qgpuinfoprovider.h"
#include <QDebug>

QMutex QGpuInfoProvider::mutex;
QGpuInfoProvider* QGpuInfoProvider::instance = nullptr;

QGpuInfoProvider &QGpuInfoProvider::getInstance()
{
    if (instance == nullptr) {
        QMutexLocker locker(&mutex);
        if (instance == nullptr) {
            instance = new QGpuInfoProvider();
        }
    }
    return *instance;
}

void QGpuInfoProvider::deleteInstance()
{
    if (instance != nullptr) {
        delete instance;
        instance = nullptr;
    }
}

QGpuInfoProvider::QGpuInfoProvider() {
    nvmlReturn_t result;

    result = nvmlInit();
    if (result != NVML_SUCCESS){
        qDebug() << "nvmlInit error";
    }


    result = nvmlDeviceGetCount(&deviceCount);
    if (result != NVML_SUCCESS){
        qDebug() << "nvmlDeviceGetCount error";
    }
}

QGpuInfoProvider::~QGpuInfoProvider()
{
    nvmlShutdown();
}

unsigned int QGpuInfoProvider::getDeviceCount() const
{
    return deviceCount;
}

QList<QGpuInfoProvider::GpuDetails> QGpuInfoProvider::getAllGpuDetails() const
{
    QList<GpuDetails> gpuList;

    nvmlReturn_t result;
    for (unsigned int i = 0; i < deviceCount; ++i) {
        nvmlDevice_t device;
        result = nvmlDeviceGetHandleByIndex(i, &device);
        if (result != NVML_SUCCESS) continue;

        char name[256];
        result = nvmlDeviceGetName(device, name, sizeof(name));
        if (result != NVML_SUCCESS) strcpy(name, "Unknown");

        char pciBusId[256];
        result = nvmlDeviceGetPciInfo_v3(device, reinterpret_cast<nvmlPciInfo_t *>(pciBusId));
        if (result != NVML_SUCCESS) strcpy(pciBusId, "Unknown");

        nvmlDeviceAttributes_t attributes;
        result = nvmlDeviceGetAttributes(device, &attributes);

        // 获取显存信息
        nvmlMemory_t memory;
        result = nvmlDeviceGetMemoryInfo(device, &memory);

        // 获取温度
        unsigned int temp = 0;
        result = nvmlDeviceGetTemperature(device, NVML_TEMPERATURE_GPU, &temp);

        // 获取功耗
        unsigned int power = 0;
        result = nvmlDeviceGetPowerUsage(device, &power);

        // 获取 UUID
        char uuid[256];
        result = nvmlDeviceGetUUID(device, uuid, sizeof(uuid));
        if (result != NVML_SUCCESS) strcpy(uuid, "Unknown");

        // 构造结构体
        GpuDetails details;
        details.name = QString::fromLocal8Bit(name);
        details.pciBusId = QString::fromLocal8Bit(pciBusId);
        details.index = i;
        details.temperature = temp;
        details.powerUsage = power;
        details.memoryTotal = memory.total;
        details.memoryUsed = memory.used;
        details.memoryFree = memory.free;
        details.uuid = QString::fromLocal8Bit(uuid);

//        运行在 GPU 上的进程信息：
//        unsigned int processCount = 0;
//        nvmlProcessInfo_t processes[1024];

//        result = nvmlDeviceGetComputeRunningProcesses(device, &processCount, processes);
//        for (unsigned int j = 0; j < processCount; ++j) {
//            ProcessInfo pinfo;
//            pinfo.pid = processes[j].pid;
//            pinfo.usedMemory = processes[j].usedGpuMemory;
//            pinfo.name = getProcessNameByPid(pinfo.pid); // 需要平台相关实现
//            details.computeProcesses.append(pinfo);
//        }

        gpuList.append(details);
    }
    return gpuList;
}

double QGpuInfoProvider::usage()
{
    if (deviceCount < 1)
        return 0;

    nvmlReturn_t result;
    double retVal = 0;

    for (int i = 0; i < deviceCount; ++i) {
        nvmlDevice_t device;
        result = nvmlDeviceGetHandleByIndex(i, &device);
        if (result != NVML_SUCCESS) continue;

        nvmlUtilization_st device_utilization;
        result = nvmlDeviceGetUtilizationRates(device, &device_utilization);
        if (result != NVML_SUCCESS) continue;

        retVal += device_utilization.gpu;
    }

    retVal = retVal / deviceCount;

    return retVal;
}
